#ifndef VECTOR_H
#define VECTOR_H

#include <iostream>
#include <math.h>

template <typename T=double> 
class Vector {
	
	public:
		
		T x, y, z;
		
		Vector():
		x(0), y(0), z(0) 
		{}

		Vector(T _x, T _y, T _z):
		x(_x), y(_y), z(_z)
		{}
		
		Vector(T *a){
			*this = *(Vector*)a;
		}
		
		double module() const {
			return sqrt(x*x + y*y + z*z);
		}
		
		Vector ort(){
			T m = sqrt(x*x + y*y + z*z);
			return Vector(x/m, y/m, z/m);
		}
		
		Vector operator + (Vector V){
			return Vector(x+V.x, y+V.y, z+V.z);
		}
		
		Vector operator / (T s){
			return Vector(x/s, y/s, z/s);
		}
		
		template <typename TT>
		Vector operator - (Vector<TT> V) const {
			return Vector(x-V.x, y-V.y, z-V.z);
		}
		
		Vector operator % (Vector V){ // Cross Product
			return Vector(y*V.z-V.y*z, z*V.x-V.z*x, x*V.y-V.x*y);
		} 
		
		T operator *(Vector V) { // Dot Product
			return x*V.x + y*V.y + z*V.z;
		};  
		
		template <typename TT>
		void operator +=(Vector<TT> V){
			x+=V.x;	y+=V.y;	z+=V.z;
		}	
		
		void operator -=(Vector V){
			x-=V.x;	y-=V.y;	z-=V.z;
		}	
		
		void operator *=(T s){
			x*=s;	y*=s;	z*=s;
		}	
		
		void operator /=(T s){
			x/=s;	y/=s;	z/=s;
		}	

		/*
		template <typename T1, typename T2>
		friend Vector<double> operator -(Vector<T1> V1, Vector<T2> V2){
			return Vector(V1.x-V2.x, V1.y-V2.y, V1.z-V2.z);
		}
		*/

		friend Vector operator *(T s, Vector V){
			return Vector(s*V.x, s*V.y, s*V.z);
		}
		
		friend Vector operator *(Vector V, T s){
			return Vector(s*V.x, s*V.y, s*V.z);
		};
		
		//template <typename T1, typename T2>
		double angle(Vector V){
			T tmp =  (this->ort()*V)/this->module();
			return tmp<=1 ? acos(tmp) : 0;
		};
		
		/*template <typename T1, typename T2>
		friend double operator ^(Vector<T1> V1, Vector<T2> V2){
			return acos( (V1.ort()*V2)/V1.module() );
		}*/
		
		operator T*(){
			return (T*)this;
		}
		
		template <typename T2>
		operator Vector<T2>(){
			
			Vector<T2> VT;
			
			VT.x = x;
			VT.y = y;
			VT.z = z;
			
			return VT;
		}
		
		template <typename T1, typename T2>
		Vector rotate(Vector<T1> V, T2 a){ // the direction vector V must be perpendicular to the rotatable vector 'this'!
			return this->module()*(cos(a)*this->ort()+ sin(a)*V.ort());		
		}
		
		void print(){
			printf("{% .15f, % .15f, % .15f}\n", x, y, z);
		}
		
		T a1(){
			T tmp = atan2(y,x);
			return tmp<0 ? (tmp + 2*M_PI) : tmp;
		}

		T a2(){
			return asin(z/module());
		}

		T sqr(){
			return x*x+y*y+z*z;
		}

		Vector setPolar(T a1, T a2, T R){
			*this   = Vector(cos(a1), sin(a1), 0);
			*this*= cos(a2);
			this->z = sin(a2);
			*this*=R; 
			return *this;
		}

};

typedef  Vector<double> DVector;
typedef  Vector<float>  FVector; 
typedef  Vector<double> dVector;
typedef  Vector<float>  fVector; 


#endif